package org.gdstash.db;

import org.gdstash.file.ARZRecord;
import org.gdstash.util.GDMsgFormatter;
import org.gdstash.util.GDMsgLogger;

import java.sql.*;
import java.util.LinkedList;
import java.util.List;

public class DBSkillButton {
    private static final String TABLE_NAME = "GDC_BUTTON_SKILL";
    private static final int ROW_BUTTON_ID = 1;
    private static final int ROW_SKILL_ID = 2;
    private static final int ROW_POS_X = 3;
    private static final int ROW_POS_Y = 4;
    private static final int ROW_OFFSET_X = 5;
    private static final int ROW_OFFSET_Y = 6;
    private static final int ROW_CIRCULAR = 7;
    private String buttonID;
    private String skillID;
    private int posX;
    private int posY;
    private int offsetX;
    private int offsetY;
    private boolean circularButton;
    private DBSkill dbSkill;

    public DBSkillButton() {
        this.buttonID = null;
        this.skillID = null;
        this.posX = 0;
        this.posY = 0;
        this.offsetX = 0;
        this.offsetY = 0;
        this.circularButton = false;
        this.dbSkill = null;
    }

    public DBSkillButton(final ARZRecord record) {
        this();
        this.buttonID = record.getFileName();
        this.skillID = record.getButtonSkillID();
        this.posX = record.getPosX();
        this.posY = record.getPosY();
        this.offsetX = record.getOffsetX();
        this.offsetY = record.getOffsetY();
        this.circularButton = record.getCircularButton();
    }

    public String getButtonID() {
        return this.buttonID;
    }

    public String getSkillID() {
        return this.skillID;
    }

    public DBSkill getSkill() {
        return this.dbSkill;
    }

    public int getPosX() {
        return this.posX;
    }

    public int getPosY() {
        return this.posY;
    }

    public int getOffsetX() {
        return this.offsetX;
    }

    public int getOffsetY() {
        return this.offsetY;
    }

    public boolean isCircularButton() {
        return this.circularButton;
    }

    public static void createTable() throws SQLException {
        final String dropTable = "DROP TABLE GDC_BUTTON_SKILL";
        final String createTable = "CREATE TABLE GDC_BUTTON_SKILL (BUTTON_ID        VARCHAR(256) NOT NULL, SKILL_ID         VARCHAR(256), POS_X            INTEGER, POS_Y            INTEGER, OFFSET_X         INTEGER, OFFSET_Y         INTEGER, CIRCULAR         BOOLEAN, PRIMARY KEY (BUTTON_ID))";
        try (final Connection conn = GDDBData.getConnection()) {
            final boolean auto = conn.getAutoCommit();
            conn.setAutoCommit(false);
            try (final Statement st = conn.createStatement()) {
                if (GDDBUtil.tableExists(conn, "GDC_BUTTON_SKILL")) {
                    st.execute(dropTable);
                }
                st.execute(createTable);
                st.close();
                conn.commit();
            } catch (SQLException ex) {
                conn.rollback();
                throw ex;
            } finally {
                conn.setAutoCommit(auto);
            }
        }
    }

    public static void delete(final String buttonID) throws SQLException {
        final String deleteEntry = "DELETE FROM GDC_BUTTON_SKILL WHERE BUTTON_ID = ?";
        try (final Connection conn = GDDBData.getConnection()) {
            final boolean auto = conn.getAutoCommit();
            conn.setAutoCommit(false);
            try (final PreparedStatement ps = conn.prepareStatement(deleteEntry)) {
                ps.setString(1, buttonID);
                ps.executeUpdate();
                ps.close();
                DBConstellationAffinity.delete(conn, buttonID);
                DBConstellationStar.delete(conn, buttonID);
                conn.commit();
            } catch (SQLException ex) {
                conn.rollback();
                final Object[] args = {buttonID, "GDC_BUTTON_SKILL"};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_DEL_TABLE_BY_ID", args);
                GDMsgLogger.addError(msg);
                GDMsgLogger.addError(ex);
                throw ex;
            } finally {
                conn.setAutoCommit(auto);
            }
        } catch (SQLException ex2) {
            throw ex2;
        }
    }

    public static void insert(final ARZRecord record) throws SQLException {
        final DBSkillButton entry = getByButtonID(record.getFileName());
        if (entry != null) {
            return;
        }
        final DBSkillButton button = new DBSkillButton(record);
        final String insert = "INSERT INTO GDC_BUTTON_SKILL VALUES (?,?,?,?,?,?,?)";
        try (final Connection conn = GDDBData.getConnection()) {
            final boolean auto = conn.getAutoCommit();
            conn.setAutoCommit(false);
            try (final PreparedStatement ps = conn.prepareStatement(insert)) {
                ps.setString(1, button.buttonID);
                ps.setString(2, button.skillID);
                ps.setInt(3, button.posX);
                ps.setInt(4, button.posY);
                ps.setInt(5, button.offsetX);
                ps.setInt(6, button.offsetY);
                ps.setBoolean(7, button.circularButton);
                ps.executeUpdate();
                ps.close();
                conn.commit();
            } catch (SQLException ex) {
                conn.rollback();
                final Object[] args = {button.buttonID, "GDC_BUTTON_SKILL"};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_INS_TABLE_BY_ID", args);
                GDMsgLogger.addLowError(msg);
                GDMsgLogger.addLowError(ex);
            } finally {
                conn.setAutoCommit(auto);
            }
        }
    }

    public static DBSkillButton getByButtonID(final String buttonID) {
        DBSkillButton button = null;
        final String command = "SELECT * FROM GDC_BUTTON_SKILL WHERE BUTTON_ID = ?";
        try (final Connection conn = GDDBData.getConnection();
             final PreparedStatement ps = conn.prepareStatement(command)) {
            ps.setString(1, buttonID);
            try (final ResultSet rs = ps.executeQuery()) {
                final List<DBSkillButton> list = wrap(rs);
                if (list.isEmpty()) {
                    button = null;
                } else {
                    button = list.get(0);
                }
                conn.commit();
            } catch (SQLException ex) {
                throw ex;
            }
        } catch (SQLException ex2) {
            final Object[] args = {buttonID, "GDC_BUTTON_SKILL"};
            final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_READ_TABLE_BY_ID", args);
            GDMsgLogger.addError(msg);
            GDMsgLogger.addError(ex2);
        }
        return button;
    }

    public static DBSkillButton getBySkillID(final String skillID) {
        DBSkillButton button = null;
        final String command = "SELECT * FROM GDC_BUTTON_SKILL, GDC_CLASSTABLE WHERE SKILL_ID = ? AND GDC_BUTTON_SKILL.BUTTON_ID = GDC_CLASSTABLE.MASTERY_ID";
        try (final Connection conn = GDDBData.getConnection();
             final PreparedStatement ps = conn.prepareStatement(command)) {
            ps.setString(1, skillID);
            try (final ResultSet rs = ps.executeQuery()) {
                final List<DBSkillButton> list = wrap(rs);
                if (list.isEmpty()) {
                    button = null;
                } else {
                    button = list.get(0);
                }
                conn.commit();
            } catch (SQLException ex) {
                throw ex;
            }
        } catch (SQLException ex2) {
            final Object[] args = {skillID, "GDC_BUTTON_SKILL"};
            final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_READ_TABLE_BY_ID", args);
            GDMsgLogger.addError(msg);
            GDMsgLogger.addError(ex2);
        }
        return button;
    }

    private static List<DBSkillButton> wrap(final ResultSet rs) throws SQLException {
        final LinkedList<DBSkillButton> list = new LinkedList<DBSkillButton>();
        while (rs.next()) {
            final DBSkillButton button = new DBSkillButton();
            button.buttonID = rs.getString(1);
            button.skillID = rs.getString(2);
            button.posX = rs.getInt(3);
            button.posY = rs.getInt(4);
            button.offsetX = rs.getInt(5);
            button.offsetY = rs.getInt(6);
            button.circularButton = rs.getBoolean(7);
            if (button.skillID != null) {
                button.dbSkill = DBSkill.get(button.skillID);
            }
            list.add(button);
        }
        return list;
    }
}
